package tt.dz.vo.request;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
import tt.dz.biz.annotation.RequestRequire;
import tt.dz.common.BusinessException;
import tt.dz.common.DzErrorCode;
import tt.dz.common.DzErrorCode.RpcRequestErrorCode;

public final class RequireFieldHolder
{
  private static final FieldRequireConfig[] NULL_FIELDS = new FieldRequireConfig[0];
  
  private static final class FieldHolderCache
  {
    private Map<Class, RequireFieldHolder.FieldRequireConfig[]> cacheMap = new ConcurrentReferenceHashMap();
    
    public static FieldHolderCache INSTANCE()
    {
      return FieldHolderCacheHold.CACHE;
    }
    
    private static final class FieldHolderCacheHold
    {
      private static RequireFieldHolder.FieldHolderCache CACHE = new RequireFieldHolder.FieldHolderCache();
    }
    
    public void putCache(Class clazz, RequireFieldHolder.FieldRequireConfig[] fields)
    {
      this.cacheMap.put(clazz, fields);
    }
    
    public RequireFieldHolder.FieldRequireConfig[] getCache(Class clazz)
    {
      return (RequireFieldHolder.FieldRequireConfig[])this.cacheMap.get(clazz);
    }
    
    public void clear()
    {
      this.cacheMap.clear();
    }
    
    public RequireFieldHolder.FieldRequireConfig[] removeCache(Class clazz)
    {
      return (RequireFieldHolder.FieldRequireConfig[])this.cacheMap.remove(clazz);
    }
    
    public boolean isContain(Class clazz)
    {
      return this.cacheMap.containsKey(clazz);
    }
  }
  
  public final FieldRequireConfig[] requestRequireFields(RpcRequestVo vo)
  {
    if (vo == null) {
      return null;
    }
    FieldHolderCache fieldHolderCache = FieldHolderCache.INSTANCE();
    Class clazz = vo.getClass();
    FieldRequireConfig[] fields = fieldHolderCache.getCache(clazz);
    if (fields != null) {
      return fields;
    }
    List<Field> fieldList = FieldUtils.getFieldsListWithAnnotation(clazz, RequestRequire.class);
    if ((fieldList == null) || (fieldList.isEmpty()))
    {
      fieldHolderCache.putCache(clazz, NULL_FIELDS);
      return null;
    }
    List<FieldRequireConfig> fieldReqConfList = new ArrayList();
    RequestRequire rrAnnotation = null;
    boolean isRequire = false;
    FieldRequireConfig fieldRequireConfig = null;
    for (Field field : fieldList)
    {
      rrAnnotation = (RequestRequire)field.getAnnotation(RequestRequire.class);
      if (rrAnnotation != null)
      {
        isRequire = rrAnnotation.required();
        fieldRequireConfig = new FieldRequireConfig(field, Boolean.valueOf(isRequire));
        fieldReqConfList.add(fieldRequireConfig);
      }
    }
    FieldRequireConfig[] fieldRequireConfigs = (FieldRequireConfig[])fieldReqConfList.toArray(new FieldRequireConfig[fieldReqConfList.size()]);
    fieldHolderCache.putCache(clazz, fieldRequireConfigs);
    return fieldRequireConfigs;
  }
  
  public static class FieldRequireConfig
  {
    private Field field;
    private Boolean isRequrie;
    
    public FieldRequireConfig() {}
    
    public FieldRequireConfig(Field field, Boolean isRequrie)
    {
      this.field = field;
      this.isRequrie = isRequrie;
    }
    
    public Object getValue(Object object)
      throws IllegalAccessException
    {
      if ((object == null) || (this.field == null)) {
        return null;
      }
      this.field.setAccessible(true);
      return this.field.get(object);
    }
    
    public boolean isNullOrEmpty(Object object)
      throws IllegalAccessException
    {
      Object obj = getValue(object);
      return (obj == null) || (obj.toString().trim().isEmpty());
    }
    
    public void validateReqiure(Object object)
      throws IllegalAccessException, BusinessException
    {
      boolean isInValidate = this.isRequrie.booleanValue() ? isNullOrEmpty(object) : false;
      if (isInValidate) {
        throw new BusinessException(DzErrorCode.RpcRequestErrorCode.PARAM_MISS.value(), "缺少必须参数[" + this.field.getName() + "]");
      }
    }
    
    public Field getField()
    {
      return this.field;
    }
    
    public void setField(Field field)
    {
      this.field = field;
    }
    
    public Boolean getRequrie()
    {
      return this.isRequrie;
    }
    
    public void setRequrie(Boolean requrie)
    {
      this.isRequrie = requrie;
    }
  }
}
